package com.mas.strategey;

import java.util.HashMap;
import java.util.Map;

import com.mas.common.Consts;
import com.mas.resource.ResourceAllocator;
import com.mas.resource.ResourceInfo;

/**
 * Extend Strategy and init with the private values of the Monitor Agent
 */
public class MonitorStrategy extends Strategy{
	
	/**
	 * the resources catalog 
	 */
	private Map resourcesCatalog;
	
	/**
	 * if the agent want to give up
	 */
	private boolean giveUp = false;
		
	public MonitorStrategy(Map resourcesCatalog)
	{
		privatePriceList = new HashMap<String,Double>();
		privatePriceList.put(Consts.RESOURCE_AMOUNT_TO_BUY, Consts.Defulte_Monitor_Price_CPU);
		privatePriceList.put(Consts.RESOURCE_START_TIME, Consts.Defulte_Monitor_Price_MEM);
		privatePriceList.put(Consts.RESOURCE_END_TIME,  Consts.Defulte_Monitor_Price_HD );
		privatePriceList.put(Consts.RESOURCE_NET, Consts.Defulte_Monitor_Price_NET);
		
		discountedFactor = Consts.Monitor_DiscountedFactor;
		pricingFactor = Consts.Monitor_pricingFactor;
		
		this.resourcesCatalog = resourcesCatalog;
	}
	
	public Consts.Response decide(Proposal proposal)
	{
		if (!resourceAvilable(proposal.getResourceInfos()))
			return Consts.Response.REJECT;
			
		Double totalPrivateValue = calcPrivateValue(proposal.getResourceInfos());
	
		// if the proposal is good for me, higher than my private value
		if (proposal.getPrice() >= totalPrivateValue * pricingFactor * (1 - discountedFactor) & proposal.getPrice() >= totalPrivateValue )
			return Consts.Response.ACCEPT;
		
		 if (giveUp)
			 return Consts.Response.REJECT;
	
		// if the proposal is not good for me, I will send my own offer
		return Consts.Response.PROPOSE_COUNTER;
	}
	
	protected void updateDiscountedFactor()
	{
		discountedFactor += Consts.Monitor_DiscountedFactorCheangesSize;
	}
	
	protected boolean resourceAvilable(ResourceInfo[] resourceInfos) {
		String resourceName;
		Double available;
		Double resourceRequired;
		ResourceAllocator resourceAllocator;

		for (int i = 0; i < resourceInfos.length; i++) {
			// get resource name and amount
			resourceName = resourceInfos[i].getResourceName();
			resourceRequired = resourceInfos[i].getRequiredUsage();

			resourceAllocator = (ResourceAllocator) resourcesCatalog.get(resourceName);
			available =  resourceAllocator.getResourceAvailable();
			
			if (resourceRequired > available)
				return false;
		}
		return true;
	}
	
	
	
	protected Proposal buildFirstProposal(Proposal curProposal) {
		Proposal newPproposal;
		String resourceName;
		Double resourceRequired;
		Double myPrice;
		Double totalPrice = 0.0;

		ResourceInfo[] resourceInfos = curProposal.getResourceInfos();
		for (int i = 0; i < resourceInfos.length; i++) {
			// get resource name and amount
			resourceName = resourceInfos[i].getResourceName();
			resourceRequired = resourceInfos[i].getRequiredUsage();

			// set my price
			myPrice = privatePriceList.get(resourceName) * pricingFactor
					* resourceRequired;
			resourceInfos[i].setPrice(myPrice);

			totalPrice += myPrice;
		}

		newPproposal = new Proposal();
		newPproposal.setResourceInfos(resourceInfos);
		newPproposal.setPrice(totalPrice);
		myLastProposal = newPproposal; // saving my proposal
		updateDiscountedFactor();
		return newPproposal;
	}

	public Proposal buildNewProposal(Proposal otherAgentProposal) {
		// first proposal, not counter proposal
		if (otherAgentProposal.getPrice() == -1)
			return buildFirstProposal(otherAgentProposal);

		return super.buildNewProposal(otherAgentProposal);
	}
	
	protected double newPrice(double myLastProposalPrice, double otherAgentProposalPrice, double myPrivateValue)
	{	
		double price;
		price = (myLastProposalPrice)* (1.0 - discountedFactor);
		
		// Can not go lower, send last proposal - after that give up
		if (price < myPrivateValue)
		{
			giveUp = true;
			return myPrivateValue;
		}
		else
			return price;
	}
	
}
